home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 2
/
Amiga Tools 2.iso
/
disktools
/
allgemein
/
noisesaver
/
txt
/
noisesaver.mod
< prev
Wrap
Text File
|
1995-03-09
|
9KB
|
343 lines
(*
(*
* $Id: NoiseSaver.mod,v 2.3 1994/11/02 14:52:34 mh Exp mh $
*
*)
*)
MODULE NoiseSaver; (* $JOIN NoiseSaver.o *)
IMPORT Conversions, Strings, SCSIDisk, Timer, Dos, Exec, sys: SYSTEM;
PROCEDURE MyProc{"MyProc"}();
VAR
OrigProc["OrigProc"] : Exec.PROC;
CallBack["CallBack"] : PROCEDURE(ior{9}:Exec.IOStdReqPtr);
MyTask["MyTask"] : Exec.TaskPtr;
ExecBase["ExecBase"] : Exec.ExecBasePtr;
CONST
Template = "DEVICE/K,TIMEOUT/N,UNIT/N,"
"T2/N,U2/N,T3/N,U3/N,T4/N,U4/N,T5/N,U5/N,T6/N,U6/N,T7/N,U7/N,T8/N,U8/N,"
"-H=HELP/S";
Version = "$VER: NoiseSaver 2.1 (02.11.94)\n\o$";
Help = "\e[1mNoiseSaver\e[0m © 1994 by Martin Horneffer\n\n"
"\e[1mNoiseSaver\e[0m stops connected SCSI-Units, whenever they have been idle\n"
"for at certain time, and automagically switches them on again when needed.\n\n"
"You can specify up to 8 units with an optional timeout each.\n"
"Default DEVICE is 'scsi.device', default TIMEOUT is 300 seconds.\n"
"If no UNIT is specified, the units 0 to 6 are tried.\n\n"
"When \e[1mNoiseSaver\e[0m is running, use\n"
" 'BREAK $NoiseSaver e' to stop the drives,\n"
" 'BREAK $NoiseSaver f' to start them and\n"
" 'BREAK $NoiseSaver c' to quit \e[1mNoiseSaver\e[0m.\n";
DefTimeout = 300;
JMP = 4EF9H;
TYPE
UnitPtr = POINTER TO Unit;
Unit = RECORD
next : UnitPtr;
unit : LONGINT;
sem : Exec.SignalSemaphore;
timer : Timer.TimeRequestPtr;
timeout: LONGINT;
ior : Exec.IOStdReqPtr;
sc : SCSIDisk.SCSICmd;
command: ARRAY 6 OF SHORTINT;
active : BOOLEAN;
stopped: BOOLEAN;
haveSem: BOOLEAN;
END;
JmpPtr = POINTER TO Jmp;
Jmp = STRUCT jmp: INTEGER; proc: Exec.PROC; END;
VAR
unitlist: UnitPtr;
lastunit: UnitPtr;
mp : Exec.MsgPortPtr;
scsiBase: Exec.LibraryPtr;
PROCEDURE TryUnit(deviceName: ARRAY OF CHAR; unit, timeout: LONGINT);
(* $CopyArrays- *)
VAR n: UnitPtr;
BEGIN
NEW(n);
n.unit := unit;
Exec.InitSemaphore(n.sem);
n.timeout := timeout;
n.ior := Exec.CreateIORequest(mp, SIZE(n.ior^));
IF n.ior # NIL THEN
IF Exec.OpenDevice(deviceName, unit, n.ior, LONGSET{}) = 0 THEN
scsiBase := n.ior.device;
n.timer := Exec.CreateIORequest(mp, SIZE(n.timer^));
IF n.timer # NIL THEN
IF Exec.OpenDevice( Timer.timerName, Timer.vBlank, n.timer, LONGSET{}) = 0 THEN
n.timer.node.error := Exec.aborted;
Exec.ReplyMsg(n.timer);
IF lastunit = NIL THEN
unitlist := n;
ELSE
lastunit.next := n;
END;
lastunit := n;
RETURN;
ELSE
Exec.DeleteIORequest(n.timer);
END;
END;
ELSE
Exec.DeleteIORequest(n.ior);
END;
END;
DISPOSE(n);
END TryUnit;
PROCEDURE (me:UnitPtr) StartStop(start: BOOLEAN);
BEGIN
IF me.active THEN RETURN END;
IF NOT start AND NOT me.haveSem THEN
Exec.ObtainSemaphore(me.sem);
me.haveSem := TRUE;
END;
me.command[0] := 1BH; (* start/stop unit *)
me.command[1] := 1; (* Bit1: immediate *)
me.command[2] := 0;
me.command[3] := 0;
me.command[4] := 0; (* Bit1: start *)
me.command[5] := 0;
IF start THEN
me.command[1] := 0;
me.command[4] := 1;
END;
me.sc.data := NIL;
me.sc.length := 0;
me.sc.command := sys.ADR(me.command);
me.sc.cmdLength:= SHORT(LEN(me.command));
me.sc.flags := SHORTSET{SCSIDisk.read};
IF start THEN
Dos.PrintF("starting unit %ld..\n", me.unit);
ELSE
Dos.PrintF("stopping unit %ld..\n", me.unit);
END;
me.ior.command := SCSIDisk.scsiCmd;
me.ior.data := sys.ADR(me.sc);
me.ior.length := SIZE(me.sc);
Exec.SendIO(me.ior);
me.active := TRUE;
me.stopped := NOT start;
END StartStop;
PROCEDURE (me:UnitPtr) Close();
BEGIN
IF me.active THEN Exec.OldWaitIO(me.ior) END;
IF me.stopped THEN
me.StartStop(TRUE);
Exec.OldWaitIO(me.ior);
IF me.haveSem THEN Exec.ReleaseSemaphore(me.sem) END;
END;
Exec.CloseDevice(me.ior);
Exec.DeleteIORequest(me.ior);
Exec.AbortIO(me.timer);
Exec.OldWaitIO(me.timer);
Exec.CloseDevice(me.timer);
Exec.DeleteIORequest(me.timer);
END Close;
PROCEDURE (me:UnitPtr) HandleIO();
BEGIN
me.active := FALSE;
Exec.Permit();
IF me.ior.error # 0 THEN
Dos.PrintF("unit %ld error: %ld, status: %ld\n",
me.unit, me.ior.error, me.sc.status);
ELSE
Dos.PrintF("unit %ld ok.\n", me.unit);
END;
IF me.haveSem AND NOT me.stopped THEN
Exec.ReleaseSemaphore(me.sem);
me.haveSem := FALSE;
Exec.AbortIO(me.timer);
END;
END HandleIO;
PROCEDURE (me:UnitPtr) HandleTimer();
VAR ok: BOOLEAN;
BEGIN
ok := me.timer.node.error = 0;
me.timer.node.command := Timer.addRequest;
me.timer.time.micro := 0;
IF ok THEN
me.timer.time.secs := 80000000H;
ELSE
me.timer.time.secs := me.timeout;
END;
Exec.SendIO(me.timer);
Exec.Permit();
IF ok # me.stopped THEN
me.StartStop(me.stopped);
END;
END HandleTimer;
PROCEDURE CallBackProc(ior{9}:Exec.IOStdReqPtr); (* $SaveRegs+ *)
(* $Debug- $StackChk- $NilChk- $ClearVars- *)
VAR u: UnitPtr;
BEGIN
u := unitlist;
WHILE u # NIL DO
IF u.ior.unit = ior.unit THEN
Exec.AbortIO(u.timer);
Exec.ObtainSemaphoreShared(u.sem);
Exec.ReleaseSemaphore(u.sem);
RETURN;
END;
u := u.next;
END;
END CallBackProc;
(* $Debug= $StackChk= $NilChk= $ClearVars= *)
PROCEDURE DispatchMsg(): BOOLEAN;
VAR msg: Exec.MessagePtr; unit: UnitPtr;
BEGIN
Exec.Forbid();
msg := Exec.GetMsg(mp);
IF msg = NIL THEN
Exec.Permit();
RETURN FALSE;
END;
unit := unitlist;
WHILE unit # NIL DO
IF unit.timer = msg THEN
unit.HandleTimer();
RETURN TRUE;
ELSIF unit.ior = msg THEN
unit.HandleIO();
RETURN TRUE;
ELSE
unit := unit.next;
END;
END;
Exec.Permit(); (* impossible *)
RETURN TRUE;
END DispatchMsg;
VAR
newProc : Exec.PROC;
args : STRUCT (as: Dos.ArgsStruct)
deviceName: Exec.STRPTR;
a: ARRAY 8 OF STRUCT
t: UNTRACED POINTER TO LONGINT;
u: UNTRACED POINTER TO LONGINT;
END;
help : LONGINT;
END;
RD : Dos.RDArgsPtr;
jmp : JmpPtr;
str : ARRAY 16 OF CHAR;
unit : UnitPtr;
timeout : LONGINT;
flags : LONGSET;
i : LONGINT;
BEGIN
IF Exec.SysBase.libNode.version < 37 THEN HALT(37) END;
ExecBase := Exec.SysBase;
sys.SETREG(0, sys.ADR(Version));
MyTask := Exec.FindTask(NIL);
mp := Exec.CreateMsgPort();
IF mp = NIL THEN HALT(20) END;
args.deviceName := sys.ADR("scsi.device");
RD := Dos.ReadArgs (Template, args, NIL);
IF (RD = NIL) OR (args.help # 0) THEN
Dos.PrintF ("Template: %s\n\nHelp:\n\n%s\n", sys.ADR(Template), sys.ADR(Help));
IF RD = NIL THEN HALT(20) ELSE HALT(0) END;
END;
timeout := DefTimeout;
FOR i := 0 TO 7 DO
IF args.a[i].t # NIL THEN
timeout := args.a[i].t^;
END;
IF (timeout > 0) & (args.a[i].u # NIL) THEN
TryUnit(args.deviceName^, args.a[i].u^, timeout);
END;
END;
IF (timeout > 0) & (unitlist = NIL) THEN
FOR i := 0 TO 6 DO
TryUnit(args.deviceName^, i, timeout);
END;
END;
IF (unitlist = NIL) OR (scsiBase = NIL) THEN HALT(10) END;
Dos.FreeArgs(RD);
Conversions.IntToStringLeft(MyTask(Dos.Process).taskNum, str);
IF Dos.SetVar("NoiseSaver", str, Strings.Length(str), LONGSET{Dos.globalOnly}) THEN END;
CallBack := CallBackProc;
jmp := sys.VAL(JmpPtr, Exec.AllocMem(SIZE(jmp^), LONGSET{Exec.public, Exec.reverse}));
IF jmp = NIL THEN HALT(20) END;
jmp.jmp := JMP;
jmp.proc := MyProc;
OrigProc := Exec.SetFunction(scsiBase, Exec.beginIO, sys.VAL(Exec.PROC, jmp));
REPEAT
flags := Exec.Wait(LONGSET{mp.sigBit,Dos.ctrlC,Dos.ctrlE,Dos.ctrlF});
IF Dos.ctrlF IN flags THEN
unit := unitlist;
WHILE unit # NIL DO
unit.StartStop(TRUE);
unit := unit.next;
END;
ELSIF Dos.ctrlE IN flags THEN
unit := unitlist;
WHILE unit # NIL DO
unit.StartStop(FALSE);
unit := unit.next;
END;
END;
IF mp.sigBit IN flags THEN
WHILE DispatchMsg() DO END;
END;
UNTIL Dos.ctrlC IN flags;
IF Dos.DeleteVar("NoiseSaver",LONGSET{Dos.globalOnly}) THEN END;
jmp.proc := OrigProc;
Exec.Forbid();
newProc := Exec.SetFunction(scsiBase, Exec.beginIO, OrigProc);
IF newProc # sys.VAL(Exec.PROC, jmp) THEN
newProc := Exec.SetFunction(scsiBase, Exec.beginIO, newProc);
END;
Exec.Permit();
CLOSE
unit := unitlist;
WHILE unit # NIL DO
lastunit := unit.next;
unit.Close();
DISPOSE(unit);
unit := lastunit;
END;
IF mp # NIL THEN Exec.DeleteMsgPort(mp) END;
END NoiseSaver.